package com.purchase.service.impl;

import com.purchase.entity.Coupon;
import com.purchase.entity.WxUser;
import com.purchase.entity.WxUserMember;
import com.purchase.mapper.CouponMapper;
import com.purchase.mapper.MemberOrderMapper;
import com.purchase.mapper.MemberPayMapper;
import com.purchase.mapper.WxUserMapper;
import com.purchase.service.MemberPayService;
import com.purchase.util.DateUtil;
import com.purchase.util.HttpClient;
import com.purchase.util.OrderIdGenerater;
import com.purchase.util.PropertiesUtil;
import com.purchase.util.wxpay.WXPayUtil;
import com.purchase.util.wxpay.app.SignValidUtilAPP;
import com.purchase.util.wxpay.jsapi.SignValidUtil;
import com.purchase.util.wxpay.jsapi.WxpayHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.crypto.hash.Hash;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import javax.servlet.http.HttpServletRequest;
import java.text.SimpleDateFormat;
import java.util.*;

@Slf4j
@Service
public class MemberPayServiceImpl implements MemberPayService {

    @Autowired
    private WxUserMapper wxUserMapper;

    @Autowired
    private MemberPayMapper memberPayMapper;

    @Autowired
    private WxpayHandler wxpayHandler;

    @Autowired
    private MemberOrderMapper memberOrderMapper;

    @Autowired
    private CouponMapper couponMapper;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Map<String, String> doUnifiedOrder(Map<String, String> paramMap) throws Exception {
        log.info("购买会员发起下单 - 开始");
        String orderId = null;
        HashMap<String, String> updMap;
        Map<String, String> map;
        try {
            orderId = paramMap.get("id");
            String wxUid = paramMap.get("wxUid");
            String totalFee = paramMap.get("price");
            String invitePhone = paramMap.get("invitePhone");
            log.debug("推荐人手机号：" + invitePhone);

            WxUser wxUser = new WxUser();
            wxUser.setWxUid(wxUid);
            wxUser = wxUserMapper.selectOne(wxUser);
            String openid = wxUser.getOpenId();

            //记录推荐人的 wxUid
            if (invitePhone != null && !"".equals(invitePhone)) {
                WxUser inviteWxUser = new WxUser();
                inviteWxUser.setVerifyPhone(invitePhone);
                inviteWxUser = wxUserMapper.selectOne(inviteWxUser);
                String inviteWxUid = inviteWxUser.getWxUid();
                HashMap<String, Object> updOrderMap = new HashMap<>();
                updOrderMap.put("inviteWxUid", inviteWxUid);
                updOrderMap.put("orderId", orderId);
                memberOrderMapper.updateOrderStatusById(updOrderMap);
                //排除自己推荐自己购买会员
                if (inviteWxUid.equals(wxUid)) {
                    updOrderMap.put("inviteWxUid", null);
                    memberOrderMapper.updateOrderStatusById(updOrderMap);
                }
            }

            //组装支付信息
            Map<String, Object> payMap = new HashMap<>();

            String id = OrderIdGenerater.generateMemberPayOrderId();
            payMap.put("id", id);
            payMap.put("memberOrderId", orderId);
            payMap.put("totalFee", totalFee);
            payMap.put("goodsBody", "叮叮仓会员" + orderId);
            payMap.put("openid", openid);
            payMap.put("tradeType", "JSAPI");
            payMap.put("member", "1");

            //入库流水
            log.debug("购买会员入库流水" + id);
            memberPayMapper.savePayOrder(payMap);

            //调用微信支付统一下单
            log.debug("购买会员调用微信支付统一下单");
            map = wxpayHandler.doUnifiedOrder(payMap);
            log.debug("购买会员微信支付统一下单返回:{}", map);

            updMap = new HashMap<>();
            updMap.put("prepayId", map.get("prepay_id"));
            updMap.put("id", id);
            memberPayMapper.modifyPayOrder(updMap);
        } catch (Exception e) {
            log.error("购买会员支付下单error,memberOrderId=" + orderId, e);
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            throw new Exception(e);
        }
        return map;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public String payNotify(HttpServletRequest request) {
        log.info("购买会员接收微信支付结果通知-开始");
        String resXml = "";
        Map resultMap = new HashMap();
        Map payOrderMap = new HashMap();
        Map updOrderMap = new HashMap();
        try {
            //接收http请求处理
            String notifyXml = HttpClient.reciveHttpReq(request, "购买会员微信支付结果通知");

            //xml转map
            Map<String, String> notifyMap = WXPayUtil.xmlToMap(notifyXml);
            log.debug("xml to map {}", notifyMap);

            //验签
            SignValidUtil.isSignatureValid(notifyMap);

            //解析微信xml
            String notifyResultCode = notifyMap.get("result_code");
            String notifyReturnCode = notifyMap.get("return_code");
            String notifyOutTradeNo = notifyMap.get("out_trade_no");
            String notifyTransactionId = notifyMap.get("transaction_id");
            String notifyReturnMsg = notifyMap.get("return_msg");
            String notifyEndTime = notifyMap.get("time_end");
            String notifyTotalFee = notifyMap.get("total_fee");

            log.debug("resultCode=" + notifyResultCode + ",returnCode=" + notifyReturnCode);

            payOrderMap.put("id", notifyOutTradeNo);
            payOrderMap.put("transactionId", notifyTransactionId);
            payOrderMap.put("endTime", notifyEndTime);
            payOrderMap.put("payFailDesc", notifyReturnMsg);

            //获取库里流水信息
            log.debug("获取库里流水信息");
            Map payOrder = memberPayMapper.getPayOrderById(payOrderMap);
            String orderId = String.valueOf(payOrder.get("member_order_id"));
            String orderTotalFee = String.valueOf(payOrder.get("total_fee"));

            //获取库里订单信息
            log.debug("获取库里订单信息");
            Map<String, Object> order = memberOrderMapper.getMemberOrderById(orderId);
            //会员订单状态
            String orderStatus = (String) order.get("order_status");
            //会员购买人
            String wxUid = (String) order.get("wx_uid");
            //会员推荐人
            String inviteWxUid = (String) order.get("invite_wx_uid");
            //购买人角色
            Integer roleId = (Integer) order.get("role_id");

            //校验订单和流水状态：如果不是待支付W或支付失败则不允许更新状态
            if (!"W".equals(orderStatus) && !"F".equals(orderStatus)) {
                log.debug("购买会员订单" + orderId + "已支付");
                resultMap.put("return_msg", "OK");
                resultMap.put("return_code", "SUCCESS");
                resXml = WXPayUtil.mapToXml(resultMap);
                return resXml;
            }

            //更新流水、订单
            if ("SUCCESS".equals(notifyResultCode) && "SUCCESS".equals(notifyReturnCode)) {

                //更新流水为成功
                log.debug("更新流水" + notifyOutTradeNo + "为成功");
                payOrderMap.put("payStatus", "S");
                memberPayMapper.modifyPayOrder(payOrderMap);

                //更新订单为成功
                updOrderMap.put("orderStatus", "S");
                updOrderMap.put("orderId", orderId);

                log.debug("更新订单" + orderId + "为成功");
                memberOrderMapper.updateOrderStatusById(updOrderMap);

                //校验返回的订单金额是否与商户侧的订单金额一致，防止数据泄漏导致出现“假通知”，造成资金损失
                log.debug("微信返回金额：" + notifyTotalFee);
                log.debug("系统流水金额：" + orderTotalFee);
                if (!notifyTotalFee.equals(yuan2fen(orderTotalFee))) {
                    log.error("系统流水金额：" + yuan2fen(orderTotalFee) + "与微信返回金额：" + notifyTotalFee + "不一致，流水号=" + notifyOutTradeNo);

                    //更新流水为失败
                    log.debug("更新流水" + notifyOutTradeNo + "为失败");
                    payOrderMap.put("payStatus", "F");
                    payOrderMap.put("payFailDesc", "系统流水金额：" + yuan2fen(orderTotalFee) + "与微信返回金额：" + notifyTotalFee + "不一致");
                    memberPayMapper.modifyPayOrder(payOrderMap);

                    //更新订单为失败
                    log.debug("更新订单" + orderId + "为失败");
                    updOrderMap.put("orderStatus", "F");
                    updOrderMap.put("orderId", orderId);
                    memberOrderMapper.updateOrderStatusById(updOrderMap);

                    //返回微信结果
                    resultMap.put("return_code", "FAIL");
                    resXml = WXPayUtil.mapToXml(resultMap);
                    return resXml;
                }
                log.debug("校验金额一致");

                //添加会员关联和设置会员有效时间
                Date startTime = null;
                Date endTime = null;
                if (roleId == 2) {
                    //2=会员
                    SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                    startTime = df.parse(DateUtil.getNow());

                    Calendar specialDate = Calendar.getInstance();
                    specialDate.setTime(startTime);
                    specialDate.add(Calendar.YEAR, 1); //特定时间的1年后
                    endTime = specialDate.getTime();

                    //给支付成功的会员绑定优惠券
                    List<Coupon> memberCoupons = couponMapper.getMemberCoupons();
                    if (memberCoupons.size() > 0) {
                        List<Map<String, Object>> receivableIdList = new ArrayList<>();
                        for (Coupon memberCoupon : memberCoupons) {
                            HashMap<String, Object> map = new HashMap<>();
                            map.put("wxUid", wxUid);
                            map.put("couponId", memberCoupon.getId());
                            receivableIdList.add(map);
                        }
                        couponMapper.createCouponUser(receivableIdList);
                    }

                }
                if (roleId == 3) {
                    //3=代购
                    SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                    startTime = df.parse(DateUtil.getNow());

                    Calendar specialDate = Calendar.getInstance();
                    specialDate.setTime(startTime);
                    specialDate.add(Calendar.YEAR, 100); //特定时间的100年后
                    endTime = specialDate.getTime();
                }

                HashMap<String, Object> memberInsMap = new HashMap<>();
                memberInsMap.put("wxUid", wxUid);
                memberInsMap.put("roleId", roleId);
                memberInsMap.put("startTime", startTime);
                memberInsMap.put("endTime", endTime);
                memberInsMap.put("status", 1);
                memberInsMap.put("inviteWxUid", inviteWxUid);

                //校验库里是否有该用户会员记录
                HashMap<String, Object> hashMap = new HashMap<>();
                hashMap.put("wxUid", wxUid);
                WxUserMember memberByWxUid = memberOrderMapper.getMemberByWxUid(hashMap);
                if (memberByWxUid != null && memberByWxUid.getStatus() == 0) {
                    //如果有，已失效，则修改
                    memberPayMapper.editMember(memberInsMap);
                } else if (memberByWxUid != null && memberByWxUid.getStatus() == 1) {
                    //如果有且有效，则延长时间
                    Calendar specialDate = Calendar.getInstance();
                    specialDate.setTime(memberByWxUid.getEndTime());
                    specialDate.add(Calendar.YEAR, 1); //特定时间的1年后
                    endTime = specialDate.getTime();
                    HashMap<String, Object> memberUpdMap = new HashMap<>();
                    memberUpdMap.put("wxUid", wxUid);
                    memberInsMap.put("roleId", roleId);
                    memberUpdMap.put("endTime", endTime);
                    memberUpdMap.put("inviteWxUid", inviteWxUid);
                    memberPayMapper.editMember(memberUpdMap);
                } else if (memberByWxUid == null) {
                    //如果没有记录，则新建
                    memberPayMapper.saveMember(memberInsMap);
                }

                log.debug("恭喜" + wxUid + "喜提会员");
            } else {
                //更新流水为失败
                log.debug("更新流水为失败");
                payOrderMap.put("payStatus", "F");
                payOrderMap.put("payFailDesc", notifyReturnMsg);
                memberPayMapper.modifyPayOrder(payOrderMap);

                //更新订单为失败
                log.debug("更新订单为失败");
                updOrderMap.put("orderStatus", "F");
                updOrderMap.put("orderId", orderId);
                memberOrderMapper.updateOrderStatusById(updOrderMap);
            }

            // 给微信返回响应报文
            resultMap.put("return_msg", "OK");
            resultMap.put("return_code", "SUCCESS");

        } catch (Exception e) {
            log.error("购买会员接收微信支付结果通知error", e);
            resultMap.put("return_code", "FAIL");
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        }
        try {
            resXml = WXPayUtil.mapToXml(resultMap);
        } catch (Exception e) {
            log.error("购买会员接收微信支付结果通知error", e);
        }
        log.info("购买会员接收微信支付结果通知-结束-{}", resXml);
        return resXml;
    }

    private String yuan2fen(String amount) {
        String currency = amount.replaceAll("[$￥,]", "");
        int index = currency.indexOf(".");
        int length = currency.length();
        Long amLong;
        if (index == -1) {
            amLong = Long.valueOf(currency + "00");
        } else if (length - index >= 3) {
            amLong = Long.valueOf((currency.substring(0, index + 3)).replace(".", ""));
        } else if (length - index == 2) {
            amLong = Long.valueOf((currency.substring(0, index + 2)).replace(".", "") + 0);
        } else {
            amLong = Long.valueOf((currency.substring(0, index + 1)).replace(".", "") + "00");
        }
        return amLong.toString();
    }

}
